package cn.hyatt.core.handler;

import cn.hyatt.common.exception.BusinessException;
import cn.hyatt.core.dto.R;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;

/**
 * 全局异常处理类
 *
 * @author hyatt
 */
@Slf4j
@RestControllerAdvice(annotations = RestController.class)
@ResponseBody
public class GlobalExceptionHandler {

    /**
     * 监听自定义业务异常
     *
     * @param e 业务异常对象
     * @return 结果
     */
    @ExceptionHandler(BusinessException.class)
    public R<Void> handleBusinessException(BusinessException e) {
        log.error(e.getMessage());
        return R.fail(e.getMessage());
    }

    @ExceptionHandler(JwtException.class)
    public R<Void> handleExpiredJwtException(JwtException e) {
        log.error(e.getMessage());
        if (e instanceof ExpiredJwtException) {
            return R.fail("登录认证以过期,请重新登录！", 401);
        }
        return R.fail(e.getMessage());
    }

    /**
     * 绑定异常
     *
     * @param e 异常对象
     * @return 结果
     */
    @ExceptionHandler(BindException.class)
    public R<Void> handleBindException(BindException e) {
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();

        StringBuilder builder = new StringBuilder();
        allErrors.forEach(it -> {
            if (it instanceof FieldError error) {
                builder.append(error.getField()).append(":")
                        .append(error.getDefaultMessage()).append(";");
            } else {
                builder.append(it.getDefaultMessage()).append(";");
            }
        });
        log.error("数据验证失败：{}", e.getMessage());
        return R.fail(builder.toString());
    }

    /**
     * 运行时异常
     *
     * @param e 异常对象
     * @return 结果
     */
    @ExceptionHandler(RuntimeException.class)
    public R<Void> handleRuntimeException(RuntimeException e) {
        log.error(e.getMessage());
        return R.fail(e.getMessage());
    }

    /**
     * 运行时异常
     *
     * @param e 异常对象
     * @return 结果
     */
    @ExceptionHandler(Exception.class)
    public R<Void> handleRuntimeException(Exception e) {
        log.error(e.getMessage());
        return R.fail(e.getMessage());
    }
}

